package com.xian.im.web.common;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.google.common.collect.Lists;
import com.xian.im.common.annotation.SpringHandlerInterceptor;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/*
 * @program: xian-code
 * @description:
 * @author: liru.xian
 * @create: 2021-01-23 17:22
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer, ApplicationContextAware {

    private ApplicationContext applicationContext;
    @Autowired
    private TokenInterceptor tokenInterceptor;
    @Autowired
    private LimitInterceptor limitInterceptor;
    @Autowired
    private BlackInterceptor blackInterceptor;

    public static List<String> stringList = new ArrayList<>();
    static {
        stringList.add("/*.html");
        stringList.add("/*/*.html");
        stringList.add("/*/*.css");
        stringList.add("/*/*.js");
        stringList.add("/webSocket/*");
        // swagger 文档
        stringList.add("/swagger-ui.html");
        stringList.add("/*/swagger-resources");
        stringList.add("/*/swagger-resources/*");
        stringList.add("/*/doc.html");
        stringList.add("/*/page/*");
        stringList.add("/webjars/*");
        stringList.add("/*/api-docs");
        /// 直播回掉通知room/notify
        stringList.add("/*/notify/*");
        // admin 监控
        stringList.add("/actuator/*");
        stringList.add("/srs/*");
        // 文件
        stringList.add("/avatar/*");
        stringList.add("/file/*");
        // 阿里巴巴 druid
        stringList.add("/druid/*");
        stringList.add("/document/*");
        stringList.add("/ws/*");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/*").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/templates").addResourceLocations("classpath:/templates/");
        registry.addResourceHandler("/swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/*").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        Map<String, Object> map = applicationContext.getBeansWithAnnotation(SpringHandlerInterceptor.class);
        List<Object> candidates = Lists.newArrayList(map.values());
        AnnotationAwareOrderComparator.sort(candidates);
        candidates.forEach(i -> {
            if (i instanceof HandlerInterceptor) {
                SpringHandlerInterceptor springHandlerInterceptor = i.getClass().getAnnotation(SpringHandlerInterceptor.class);
                InterceptorRegistration registration = registry.addInterceptor((HandlerInterceptor) i);
                if (springHandlerInterceptor.includePatterns().length != 0) {
                    registration.addPathPatterns(springHandlerInterceptor.includePatterns());
                }
                if (springHandlerInterceptor.excludepatterns().length != 0) {
                    registration.excludePathPatterns(springHandlerInterceptor.excludepatterns());
                }
            }
        });
        registry.addInterceptor(tokenInterceptor)
                .addPathPatterns("/*")
                .excludePathPatterns(stringList)
                .excludePathPatterns("/*/login");
        registry.addInterceptor(limitInterceptor).addPathPatterns("/*");
        registry.addInterceptor(blackInterceptor).addPathPatterns("/*");
    }


    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/*", buildConfig());
        return new CorsFilter(source);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private CorsConfiguration buildConfig() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*"); // 1 设置访问源地址
        corsConfiguration.addAllowedHeader("*"); // 2 设置访问源请求头
        corsConfiguration.addAllowedMethod("*"); // 3 设置访问源请求方法
        return corsConfiguration;
    }

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        //设置自定义日期格式转换器
        ObjectMapper objectMapper = new ObjectMapper();
        JavaTimeModule module = new JavaTimeModule();
        //支持LocalDateTime类型
        module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        module.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        objectMapper.registerModule(module);
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        //设置中文编码格式
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(Lists.newArrayList(MediaType.APPLICATION_JSON,new MediaType("application","*+json")));
        //添加到converter中
        converters.add(mappingJackson2HttpMessageConverter);
    }

    @Bean
    public RequestContextListener requestContextListener() {
        return new RequestContextListener();
    }


}